<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick } from 'vue'
import G6, { Graph, GraphData, INode } from '@antv/g6'
import { registerDeviceNode, DEVICE_NODE } from './customNodes/deviceNode'
import { UNKNOWN_CATEGORY } from '@/config'
import { ElMessageBox } from 'element-plus'
import { reduce } from 'lodash'

// 拓扑组件类型
interface NodeBusinessData {
  id: string
  category: string
  // 其他业务属性...
  ip?: string // 添加ip属性
}

interface GraphNodeData {
  id: string
  x?: number
  y?: number
  size?: number
  color?: string
  icon?: string
  label?: string
}

interface EdgeData {
  id: string
  source: string
  target: string
}

interface NodeUIData {
  nodes: GraphNodeData[]
  edges: EdgeData[]
}

interface TopologyData {
  mode: 'edit' | 'display'
  categories: string[]
  nodeBusinessData: NodeBusinessData[]
  nodeUIData: NodeUIData
}

const props = withDefaults(defineProps<TopologyData>(), {
  mode: 'edit',
})

const emit = defineEmits<{
  (e: 'update:nodeBusinessData', value: NodeBusinessData[]): void
  (e: 'update:nodeUIData', value: NodeUIData): void
  (e: 'nodeDblclick', nodeData: { id: string; ip?: string }): void // 新增双击事件
}>()

// 图表相关变量和函数
const containerRef = ref<HTMLElement | null>(null)
const graphRef = ref<Graph | null>(null)

const handleEdgeClick = async (evt: { item: any }) => {
  if (props.mode === 'edit') {
    try {
      await ElMessageBox.confirm('确定要删除这条连接线吗？', '确认删除', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      })
      const edge = evt.item
      graphRef.value?.removeItem(edge)
    } catch (e) {
      console.log('删除操作已取消')
    }
  }
}

const initGraph = () => {
  if (!containerRef.value) return

  // 销毁旧图表
  if (graphRef.value) {
    graphRef.value.destroy()
  }
  console.log('init-graph')

  registerDeviceNode()

  const width = containerRef.value.clientWidth
  const height = getGraphHeight()

  const graph = new G6.Graph({
    container: containerRef.value,
    width,
    height,
    modes: graphModes.value,
    defaultNode: {
      type: DEVICE_NODE,
      mode: props.mode,
    },
    defaultEdge: {
      type: 'line',
      style: {
        stroke: '#999',
        lineWidth: 2,
      },
    },
    edgeStateStyles: {
      hover: {
        stroke: '#1890ff',
        lineWidth: 3,
      },
    },
    renderer: 'svg',
  })

  // 添加事件监听
  graph.on('node:dblclick', handleNodeDblClick)
  graph.on('node:mouseover', handleNodeMouseOver)
  graph.on('node:mouseout', handleNodeLeave)
  graph.on('edge:click', handleEdgeClick)

  graphRef.value = graph

  // 渲染分组和节点
  renderGraph()
}

const getGraphHeight = () => {
  return reduce(props.categories, sum => sum + CATEGORY_HEIGHT, 0)
}
const renderGraph = () => {
  if (!graphRef.value || !containerRef.value) return

  const width = containerRef.value.clientWidth || 800
  const height = getGraphHeight()

  // 更新图表尺寸
  graphRef.value.changeSize(width, height)

  // 创建业务节点
  const nodes = filteredGraphData.value.nodes.map(node => {
    const x = node.x ?? Math.random() * (width - 100) + 50
    const y = node.y ?? Math.random() * (height - 100) + 50

    return {
      id: node.id,
      type: DEVICE_NODE,
      size: node.size || 40,
      color: node.color || '#5B8FF9',
      icon: node.icon,
      label: node.label,
      x,
      y,
      category: node.category,
    }
  })

  const data: GraphData = {
    nodes: [...nodes],
    edges: filteredGraphData.value.edges,
  }

  nextTick(() => {
    graphRef.value?.data(data)
    graphRef.value?.render()
    // 创建背景分组
    createBackgroundGroups(graphRef.value, width, height)
    console.log('Graph rendered with new data')
  })
}

const CATEGORY_HEIGHT = 200
const createBackgroundGroups = (
  graph: Graph,
  width: number,
  height: number
) => {
  const canvas = graph.get('canvas')
  const backgroundGroup = canvas.addGroup({
    id: 'background-group',
    x: 0,
    y: 0,
    width,
    height,
    zIndex: -1,
  })
  backgroundGroup.toBack()

  let currentY = 0
  props.categories.forEach(category => {
    const categoryHeight = CATEGORY_HEIGHT

    if (props.mode === 'display' && category === UNKNOWN_CATEGORY) return

    backgroundGroup.addShape('rect', {
      attrs: {
        x: 0,
        y: currentY,
        width,
        height: categoryHeight,
        fill: '#f5f5f5',
        stroke: '#d9d9d9',
        radius: 4,
      },
      name: `group-bg-${category}`,
    })

    // 添加分组标题
    backgroundGroup.addShape('text', {
      attrs: {
        text: category,
        x: 10,
        y: currentY + 20,
        textAlign: 'left',
        fill: '#666',
        fontSize: 14,
        fontWeight: 'bold',
      },
      name: `group-title-${category}`,
    })

    currentY += categoryHeight
  })

  return backgroundGroup
}

// 节点相关函数
// status: warning, normal
const setNodeStatus = (nodeId, status) => {
  graphRef.value.setItemState(nodeId, 'status', status)
}
const handleNodeDblClick = (evt: { item: INode }) => {
  const node = evt.item
  const model = node.getModel()
  const businessNode = props.nodeBusinessData.find(n => n.id === model.id)

  emit('nodeDblclick', {
    id: model.id as string,
    ip: businessNode?.ip,
  })
}

const handleNodeMouseOver = (evt: { item: INode }) => {
  const node = evt.item
  const model = node.getModel()
  graphRef.value.setItemState(model.id, 'hover', true)
}
const handleNodeLeave = (evt: { item: INode }) => {
  const node = evt.item
  const model = node.getModel()
  graphRef.value.setItemState(model.id, 'hover', false)
}

const mergedNodes = computed(() => {
  const uiNodesMap = new Map<string, GraphNodeData>()
  props.nodeUIData.nodes.forEach(node => uiNodesMap.set(node.id, node))

  return props.nodeBusinessData.map(businessNode => {
    const uiNode = uiNodesMap.get(businessNode.id) || {
      id: businessNode.id,
    }
    return {
      ...uiNode,
      ...businessNode,
      label: businessNode.name,
    }
  })
})

const filteredGraphData = computed(() => {
  return {
    nodes: mergedNodes.value,
    edges: props.nodeUIData.edges,
  }
})

const graphModes = computed(() => {
  if (props.mode === 'display') {
    return {
      default: [],
    }
  }
  return {
    default: [
      'drag-node',
      { type: 'create-edge', trigger: 'click' },
      'delete-edge',
    ],
  }
})

// 保存相关函数
const save = () => {
  if (!graphRef.value) return null

  const graphData = graphRef.value.save()

  return {
    nodeBusinessData: [...props.nodeBusinessData],
    nodeUIData: graphData,
  }
}

const removeLinesByNodeId = ({ nodeId }) => {
  if (!graphRef.value) return

  // 获取所有与该节点相连的边
  const edges = graphRef.value.getEdges()
  const edgesToRemove = edges.filter(edge => {
    const model = edge.getModel()
    return model.source === nodeId || model.target === nodeId
  })

  // 批量删除这些边
  edgesToRemove.forEach(edge => {
    graphRef.value.removeItem(edge)
  })
}

// 暴露save方法
defineExpose({
  save,
  setNodeStatus,
  removeLinesByNodeId,
})

watch(
  () => props.nodeBusinessData,
  () => {
    setTimeout(() => {
      renderGraph()
    }, 400)
  },
  { deep: true }
)

// 初始化
onMounted(() => {
  nextTick(() => {
    initGraph()
  })
})

// 响应式调整图表大小
window.addEventListener('resize', () => {
  if (graphRef.value) {
    renderGraph()
  }
})
</script>

<template>
  <div ref="containerRef" class="topology-container"></div>
</template>

<style scoped>
.topology-container {
  width: 100%;
  height: 100%;
  border: 1px solid #e8e8e8;
  border-radius: 4px;
}
</style>
